package org.jeecg.modules.xindian.reconciliation.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.jeecg.modules.xindian.reconciliation.controller.req.PolicyRelationExcel;
import org.jeecg.modules.xindian.reconciliation.entity.*;
import org.jeecg.modules.xindian.reconciliation.enums.RelationType;
import org.jeecg.modules.xindian.reconciliation.enums.SettlementState;
import org.jeecg.modules.xindian.reconciliation.enums.StatisticsPolicyStateEnum;
import org.jeecg.modules.xindian.reconciliation.mapper.PolicySettlementTypeStatisticsMapper;
import org.jeecg.modules.xindian.reconciliation.mapper.SalesmanSettlementInfoMapper;
import org.jeecg.modules.xindian.reconciliation.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: 业务员结算信息
 * @Author: jeecg-boot
 * @Date:   2024-04-11
 * @Version: V1.0
 */
@Service
@Slf4j
public class SalesmanSettlementInfoServiceImpl extends ServiceImpl<SalesmanSettlementInfoMapper, SalesmanSettlementInfo> implements ISalesmanSettlementInfoService {

    @Autowired
    private ISalesmanManagerRateService iSalesmanManagerRateService;
    @Autowired
    private ISalesmanService salesmanService;
    @Autowired
    private IInsuranceStatisticsService insuranceStatisticsService;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private IPolicySettlementTypeStatisticsService policySettlementStatisticsService;
    @Autowired
    private PolicySettlementTypeStatisticsMapper policySettlementTypeStatisticsMapper;



    public void synchronizeMouth(Date date){
        String lastMounthString = DateUtil.format(date,"yyyy-MM");
        List<SalesmanManagerRate> salesmanManagerRates =   iSalesmanManagerRateService.listAllEnableRate();
        Map<String,List<SalesmanManagerRate>> salesmanRateMaps=  salesmanManagerRates.stream().collect(Collectors.groupingBy(SalesmanManagerRate::getSalesmanId));
        Assert.notEmpty(salesmanManagerRates,"未找到业务的配置信息,请先配置业务员管理的客户");
        Map<String,Salesman> salesmanMap = salesmanService.listByIds(salesmanManagerRates.stream().map(SalesmanManagerRate::getSalesmanId)
                .collect(Collectors.toList())).stream().collect(Collectors.toMap(Salesman::getId, Function.identity()));
        //同步上个月的状态
        //查找配置的客户记录信息
        List<InsuranceStatistics> lastMounthStatistics = insuranceStatisticsService.loadByPolicyHolderName(salesmanManagerRates.stream().map(SalesmanManagerRate::getCompany)
                .collect(Collectors.toList()),date);
        Map<String,List<InsuranceStatistics>> statisticsPolicyHolderName =  lastMounthStatistics.stream().collect(Collectors.groupingBy(InsuranceStatistics::getPayAccountName));
        //构建主记录
        List<SalesmanSettlementInfo> addSettlementInfo = new ArrayList<>();
        List<PolicySettlementTypeStatistics> addSettlementPolicyRelation = new ArrayList<>();
        salesmanMap.keySet().forEach(dt->{
            List<PolicySettlementTypeStatistics> addList = new ArrayList<>();
            SalesmanSettlementInfo info = new SalesmanSettlementInfo();
            info.setId(IdUtil.fastUUID());
            info.setSalesman(salesmanMap.get(dt).getName());
            info.setSalesmanId(dt);
            info.setBenefit(BigDecimal.ZERO);
            info.setDate(lastMounthString);
            info.setInsuranceAmt(BigDecimal.ZERO);
            info.setInsuranceNum(0);
            info.setState(SettlementState.CHECKING);

            List<SalesmanManagerRate>   oneSalesmanRate  =  salesmanRateMaps.get(dt);
            oneSalesmanRate.forEach(cof -> {
                cof.buildConfigs();
                Long numbers = lambdaQuery().eq(SalesmanSettlementInfo::getSalesmanId, cof.getSalesmanId()).eq(SalesmanSettlementInfo::getDate, lastMounthString).count();
                if (numbers != 0) {
                    log.warn("业务员{}账单{}已被初始化过,不在重复加载", cof.getSalesmanId(), lastMounthString);
                    return;
                }
                List<InsuranceStatistics> tag = statisticsPolicyHolderName.get(cof.getCompany());
                if (CollectionUtils.isEmpty(tag)) {
                    return;
                }
                //获取当前单位的统计列表
                List<SalesmanManagerRate.OtherAreaRateConfig> configs = cof.getConfigs();
                Map<String,BigDecimal> plantFormConfig = new HashMap<>();
                configs.forEach(otherAreaRateConfig -> {
                    otherAreaRateConfig.getPlatform().forEach(pla->{
                        plantFormConfig.put(pla+otherAreaRateConfig.getInsuranceCompany(),otherAreaRateConfig.getRate());
                    });
                });
                tag.forEach(ctd->{
                    BigDecimal rate = null;
                    String key = ctd.getPlatformCode()+ctd.getInsuranceCompany();
                    if(plantFormConfig.containsKey(ctd.getPlatformCode()+ctd.getInsuranceCompany())){
                        rate = plantFormConfig.get(key);
                    }else {
                        rate = cof.getFixRate();
                    }
                    PolicySettlementTypeStatistics settlementStatistics =  policySettlementStatisticsService.build(ctd, info.getId(), RelationType.SALESMAN,rate);
                    settlementStatistics.setSalesmanId(info.getSalesmanId());
                    settlementStatistics.setSalesmanName(info.getSalesman());
                    settlementStatistics.setDate(info.getDate());
                    addList.add(settlementStatistics);
                });
            });
            if(CollectionUtils.isNotEmpty(addList)){
                computerTotal(info, addList);
                addSettlementInfo.add(info);
                addSettlementPolicyRelation.addAll(addList);
            }
        });

        Map<String, PolicySettlementTypeStatistics> fromDBs = policySettlementStatisticsService.queryByPolicyNos(addSettlementPolicyRelation.stream().map(PolicySettlementTypeStatistics::getPolicyNo).collect(Collectors.toList()));
        transactionTemplate.execute(status -> {
            saveBatch(addSettlementInfo);
            List<PolicySettlementTypeStatistics> addSta = new ArrayList<>();
            addSettlementPolicyRelation.forEach(relea->{
                PolicySettlementTypeStatistics fromDB = fromDBs.get(relea.getPolicyNo());
                if (fromDB == null) {
                    addSta.add(relea);
                } else {
                    relea.setInsuranceFee(fromDB.getInsuranceFee());
                    relea.setInsuranceFeeRate(fromDB.getInsuranceFeeRate());
                    relea.setInsuranceSettlementId(fromDB.getInsuranceSettlementId());
                    relea.setType(RelationType.SALESMAN.name());
                    addSta.add(relea);
                }
            });
            policySettlementStatisticsService.saveBatch(addSta);
            return null;
        });
    }
    public void synchronizeLastMonth() {
            //查询数据是否被初始化
        Date lastMounth = DateUtil.offsetMonth(new Date(), -1);
//        Date lastMounth = DateUtil.parseDate("2024-03-02");
        synchronizeMouth(lastMounth);
    }

    @Override
    public void confirmPolicy(String id) {
        SalesmanSettlementInfo settlementInfo = getById(id);
        Assert.isTrue(settlementInfo.getState().equals(SettlementState.CHECKING), "当前保单状态不是待确定状态,无法确定");
        settlementInfo.setState(SettlementState.CHECKED);
        updateById(settlementInfo);
    }

    @Override
    public void loadSettlementByUpLoadFile(String id, List<PolicyRelationExcel> relationExcels) {
        List<PolicySettlementTypeStatistics> addRelations = new ArrayList<>();
        SalesmanSettlementInfo settlementInfo = getById(id);
        Salesman salesman =  salesmanService.getById(settlementInfo.getSalesmanId());
        Map<String,PolicyRelationExcel> rateMap = relationExcels.stream().collect(Collectors.toMap(PolicyRelationExcel::getPolicyNo,Function.identity()));
        List<String> policyNos = relationExcels.stream().map(PolicyRelationExcel::getPolicyNo).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(policyNos)) {
            settlementInfo.setInsuranceAmt(BigDecimal.ZERO);
            settlementInfo.setBenefit(BigDecimal.ZERO);
            settlementInfo.setInsuranceNum(0);
            transactionTemplate.execute(status -> {
                //清理历史数据
                policySettlementTypeStatisticsMapper.deleteSalesmanSettlementInfo(id);
                updateById(settlementInfo);
                return null;
            });
        } else {
            List<SalesmanManagerRate> rates = iSalesmanManagerRateService.queryBySalesmanId(settlementInfo.getSalesmanId());
            Assert.notEmpty(rates, "业务员{}保费配置信息未配置", salesman.getName());
            //加载保单数据
            List<InsuranceStatistics> statistics = insuranceStatisticsService.lambdaQuery().in(InsuranceStatistics::getPolicyNo, policyNos).list();
            List<String> orders = statistics.stream().map(InsuranceStatistics::getPolicyNo).collect(Collectors.toList());
            List<String> uploadNos = new ArrayList<>(policyNos);
            uploadNos.removeAll(orders);
            Assert.isTrue(uploadNos.size() ==0,"上传保单的保单号{}不存在,", StringUtils.collectionToCommaDelimitedString(uploadNos));
            List<String> ids = new ArrayList<>(policyNos);
            ids.removeAll(orders);
            Assert.isTrue(CollectionUtils.isEmpty(ids), "统计数据中未找到以下保单数据{},请核对", StringUtils.collectionToDelimitedString(ids, ","));
            //根据保单计算信息
            statistics.stream().filter(one -> Arrays.asList(StatisticsPolicyStateEnum.CBZ.name(), StatisticsPolicyStateEnum.YCB.name()).contains(one.getPolicyState())).forEach(cof -> {
                PolicyRelationExcel rate = rateMap.get(cof.getPolicyNo());
                Assert.notNull(rate, "保单{}费率不存在", rate.getPolicyNo());
                PolicySettlementTypeStatistics settlementStatistics = policySettlementStatisticsService.build(cof, id, RelationType.SALESMAN, rate.getRate());
                settlementStatistics.setSalesmanId(settlementInfo.getSalesmanId());
                settlementStatistics.setSalesmanName(settlementInfo.getSalesman());
                settlementStatistics.setDate(settlementInfo.getDate());
                addRelations.add(settlementStatistics);
            });
            //统计汇总数据
            computerTotal(settlementInfo, addRelations);
            transactionTemplate.execute(status -> {
                //清理历史数据
                policySettlementStatisticsService.process(addRelations, settlementInfo.getId(), settlementInfo.getDate(),RelationType.SALESMAN);
                updateById(settlementInfo);
                return null;
            });
        }
    }

    @Override
    public IPage<SalesmanSettlementInfo> querySalesmanSettlementInfo(IPage<SalesmanSettlementInfo> page, String date) {
        return getBaseMapper().querySalesmanSettlementInfo(page,date);
    }

    private void computerTotal(SalesmanSettlementInfo settlementInfo, List<PolicySettlementTypeStatistics> relations) {
        settlementInfo.setInsuranceNum(relations.size());
        AtomicReference<BigDecimal> insuranceAmt = new AtomicReference<>(BigDecimal.ZERO);
        AtomicReference<BigDecimal> benefit = new AtomicReference<>(BigDecimal.ZERO);
        relations.forEach(relation -> {
            BigDecimal amt =    insuranceAmt.get().add(relation.getCost());
            BigDecimal  fit = benefit.get().add(relation.getSalesmanFee());
            insuranceAmt.set(amt);
            benefit.set(fit);
        });
        settlementInfo.setState(SettlementState.CHECKING);
        settlementInfo.setInsuranceAmt(insuranceAmt.get());
        settlementInfo.setBenefit(benefit.get());
    }
}
